<?php
/*
** Copyright (C) 2001-2025 Zabbix SIA
**
** This program is free software: you can redistribute it and/or modify it under the terms of
** the GNU Affero General Public License as published by the Free Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
** See the GNU Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public License along with this program.
** If not, see <https://www.gnu.org/licenses/>.
**/


/**
 * @var CView $this
 */

?>
<script>
	const view = new class {

		init({ldap_servers, ldap_default_row_index, db_authentication_type, saml_provision_groups,
				saml_provision_media, templates, mfa_methods, mfa_default_row_index, is_http_auth_allowed,
				saml_idp_certificate_exists, saml_sp_certificate_exists, saml_sp_private_key_exists,
				saml_certificate_max_filesize, saml_private_key_max_filesize, saml_filesize_error_message,
				saml_certs_editable
		}) {
			this.form = document.getElementById('authentication-form');
			this.db_authentication_type = db_authentication_type;
			this.saml_provision_status = document.getElementById('saml_provision_status');
			this.saml_provision_groups_table = document.getElementById('saml-group-table');
			this.saml_media_type_mapping_table = document.getElementById('saml-media-type-mapping-table');
			this.ldap_jit_status = document.getElementById('ldap_jit_status');
			this.ldap_servers_table = document.getElementById('ldap-servers');
			this.templates = templates;
			this.is_http_auth_allowed = is_http_auth_allowed;
			this.ldap_provisioning_fields = this.form.querySelectorAll(
				'[name="ldap_jit_status"],[name="ldap_case_sensitive"],[name="jit_provision_interval"]'
			);
			this.jit_provision_interval = this.form.querySelector('[name="jit_provision_interval"]');
			this.ldap_auth_enabled = this.form.querySelector('[type="checkbox"][name="ldap_auth_enabled"]');
			this.mfa_table = document.getElementById('mfa-methods');
			this.saml_idp_certificate_exists = saml_idp_certificate_exists;
			this.saml_sp_certificate_exists = saml_sp_certificate_exists;
			this.saml_sp_private_key_exists = saml_sp_private_key_exists;
			this.saml_certificate_max_filesize = saml_certificate_max_filesize;
			this.saml_private_key_max_filesize = saml_private_key_max_filesize;
			this.saml_filesize_error_message = saml_filesize_error_message;
			this.saml_certs_editable = saml_certs_editable;
			const saml_readonly = !this.form.querySelector('[type="checkbox"][name="saml_auth_enabled"]').checked;
			const ldap_disabled = this.ldap_auth_enabled === null || !this.ldap_auth_enabled.checked;
			const mfa_readonly = !this.form.querySelector('[type="checkbox"][name="mfa_status"]').checked;

			this._addEventListeners();
			this._addLdapServers(ldap_servers, ldap_default_row_index);
			this.#setTableVisiblityState(this.ldap_servers_table, ldap_disabled);
			this.#disableRemoveLinksWithUserGroups(this.ldap_servers_table);
			this._renderProvisionGroups(saml_provision_groups);
			this.#setTableVisiblityState(this.saml_provision_groups_table, saml_readonly);
			this._renderProvisionMedia(saml_provision_media);
			this.#setTableVisiblityState(this.saml_media_type_mapping_table, saml_readonly)
			this.#addMfaMethods(mfa_methods, mfa_default_row_index);
			this.#setTableVisiblityState(this.mfa_table, mfa_readonly);
			this.#disableRemoveLinksWithUserGroups(this.mfa_table);

			if (this.saml_certs_editable) {
				this.#updateSpCertificateRequiredState();
			}

			this.form.querySelector('[type="checkbox"][name="saml_auth_enabled"]').dispatchEvent(new Event('change'));
		}

		_addEventListeners() {
			this.#addLdapSettingsEventListeners();

			if (this.is_http_auth_allowed) {
				document.getElementById('http_auth_enabled').addEventListener('change', (e) => {
					this.form.querySelectorAll('[name^=http_]').forEach(field => {
						if (!field.isSameNode(e.target)) {
							field.disabled = !e.target.checked;
						}
					});

					if (e.target.checked) {
						let form_fields = this.form.querySelectorAll('[name^=http_]');

						const http_auth_enabled = document.getElementById('http_auth_enabled');
						overlayDialogue({
							title: <?= json_encode(_('Confirm changes')) ?>,
							content: document.createElement('span').innerText = <?= json_encode(
								_('Enable HTTP authentication for all users.')
							) ?>,
							buttons: [
								{
									title: <?= json_encode(_('Cancel')) ?>,
									cancel: true,
									class: '<?= ZBX_STYLE_BTN_ALT ?>',
									action: function () {
										for (const form_field of form_fields) {
											if (form_field !== http_auth_enabled) {
												form_field.disabled = true;
											}
										}

										http_auth_enabled.checked = false;
										document.getElementById('tab_http').setAttribute('data-indicator-value', '0');
									}
								},
								{
									title: <?= json_encode(_('Ok')) ?>,
									focused: true,
									action: function () {}
								}
							]
						}, {
							position: Overlay.prototype.POSITION_CENTER,
							trigger_element: e.target
						});
					}
				});
			}

			this.form.querySelector('[type="checkbox"][name="saml_auth_enabled"]').addEventListener('change', (e) => {
				const is_readonly = !e.target.checked;

				this.form.querySelectorAll('.saml-enabled').forEach(field => {
					field.toggleAttribute('readonly', is_readonly);
					field.toggleAttribute('disabled', is_readonly);
					field.setAttribute('tabindex', is_readonly ? -1 : 0);
				});
				this.#setTableVisiblityState(this.saml_provision_groups_table, is_readonly);
				this.#setTableVisiblityState(this.saml_media_type_mapping_table, is_readonly);
			});

			this.saml_provision_status.addEventListener('change', (e) => {
				this.form.querySelectorAll('.saml-provision-status').forEach(field =>
					field.classList.toggle('<?= ZBX_STYLE_DISPLAY_NONE ?>', !e.target.checked)
				);
			});

			for (const button of this.form.querySelectorAll('.js-saml-cert-change-button')) {
				button.addEventListener('click', e => {
					const container = button.nextElementSibling.classList.contains('js-saml-cert-input') ? button.nextElementSibling : null;

					if (container) {
						const textarea = container.querySelector('textarea');
						container.style.display = '';
						textarea.classList.add('saml-enabled');
						textarea.removeAttribute('disabled');
						button.remove();
					}
				});
			}

			for (const button of this.form.querySelectorAll('.js-saml-cert-file-button')) {
				button.addEventListener('click', e => {
					const textarea = e.target.parentNode.querySelector('textarea');
					const extension_filter = textarea.name === 'sp_private_key'
						? '.key, .pem, .txt'
						: '.cer, .crt, .pem, .txt';

					this.#setSelectedFileContentTo(textarea, extension_filter);
				});
			}

			this.saml_provision_groups_table.addEventListener('click', (e) => {
				if (e.target.classList.contains('disabled')) {
					return;
				}
				else if (e.target.classList.contains('js-add')) {
					this.editSamlProvisionGroup();
				}
				else if (e.target.classList.contains('js-edit')) {
					this.editSamlProvisionGroup(e.target.closest('tr'));
				}
				else if (e.target.classList.contains('js-remove')) {
					e.target.closest('tr').remove();
				}
			});

			this.saml_media_type_mapping_table
				.addEventListener('click', (e) => {
					if (e.target.classList.contains('disabled')) {
						return;
					}
					else if (e.target.classList.contains('js-add')) {
						this.editSamlProvisionMedia();
					}
					else if (e.target.classList.contains('js-edit')) {
						this.editSamlProvisionMedia(e.target.closest('tr'));
					}
					else if (e.target.classList.contains('js-remove')) {
						e.target.closest('tr').remove();
					}
				});

			this.form.addEventListener('submit', (e) => {
				if (!this._authFormSubmit()) {
					e.preventDefault();
				}
			});

			this.mfa_table.addEventListener('click', (e) => {
				if (e.target.classList.contains('disabled')) {
					return;
				}
				else if (e.target.classList.contains('js-add')) {
					this.editMfaMethod();
				}
				else if (e.target.classList.contains('js-edit')) {
					this.editMfaMethod(e.target.closest('tr'));
				}
				else if (e.target.classList.contains('js-remove')) {
					const table = e.target.closest('table');
					const mfaid_input = e.target.closest('tr')
						.querySelector('input[name$="[mfaid]"]');

					if (mfaid_input !== null) {
						const input = document.createElement('input');
						input.type = 'hidden';
						input.name = 'mfa_removed_mfaids[]';
						input.value = mfaid_input.value;
						this.form.appendChild(input);
					}

					e.target.closest('tr').remove();

					if (table.querySelector('input[name="mfa_default_row_index"]:checked') === null) {
						const default_mfa = table.querySelector('input[name="mfa_default_row_index"]');

						if (default_mfa !== null) {
							default_mfa.checked = true;
						}
					}
				}
			});

			this.form.querySelector('[type="checkbox"][name="mfa_status"]').addEventListener('change', (e) => {
				const is_readonly = !e.target.checked;
				const default_index = this.form.querySelector('input[name="mfa_default_row_index"]:checked');
				const default_index_hidden = this.form.querySelector('[type="hidden"][name="mfa_default_row_index"]');

				this.#setTableVisiblityState(this.mfa_table, is_readonly);
				this.#disableRemoveLinksWithUserGroups(this.mfa_table);

				if (is_readonly && default_index) {
					default_index_hidden.value = default_index.value;
				}
			});

			if (this.saml_certs_editable) {
				[...this.#getSpCertificateCheckboxes()].forEach(checkbox => {
					checkbox.addEventListener('change', () => {
						this.#updateSpCertificateRequiredState();
					})
				});
			}
		}

		#getSpCertificateCheckboxes() {
			const selector = [
				'sign_messages', 'sign_assertions', 'sign_authn_requests', 'sign_logout_requests',
				'sign_logout_responses', 'encrypt_nameid', 'encrypt_assertions'
			].map(n => `[name="${n}"]`).join(',');

			return this.form.querySelectorAll(selector);
		}

		#isSpCertificateRequired() {
			const checked = [...this.#getSpCertificateCheckboxes()].filter(checkbox => checkbox.checked);

			return checked.length > 0;
		}

		#updateSpCertificateRequiredState() {
			const required = this.#isSpCertificateRequired();

			this.form.querySelector('label[for="sp_private_key"]')
				.classList.toggle(ZBX_STYLE_FIELD_LABEL_ASTERISK, required);
			this.form.querySelector('textarea[name="sp_private_key"]')
				.toggleAttribute('aria-required', ZBX_STYLE_FIELD_LABEL_ASTERISK, required);
			this.form.querySelector('label[for="sp_certificate"]')
				.classList.toggle(ZBX_STYLE_FIELD_LABEL_ASTERISK, required);
			this.form.querySelector('textarea[name="sp_certificate"]')
				.toggleAttribute('aria-required', ZBX_STYLE_FIELD_LABEL_ASTERISK, required);
		}

		#setSelectedFileContentTo(textarea, extension_filter) {
			const input = document.createElement('input');
			const wrapper = textarea.parentElement;

			input.type = 'file';
			input.accept = extension_filter;

			textarea.addEventListener('input', e => {
				wrapper.querySelector('.error')?.remove();
				textarea.classList.remove('has-error');
			});

			input.addEventListener('change', e => {
				wrapper.querySelector('.error')?.remove();
				textarea.classList.remove('has-error');

				const file = e.target.files && e.target.files[0] ? e.target.files[0] : null;

				if (!file) {
					return;
				}

				const max_filesize = textarea.id === 'sp_private_key'
					? this.saml_private_key_max_filesize
					: this.saml_certificate_max_filesize;

				if (file.size > max_filesize) {
					const error_span = document.createElement('span');

					error_span.className = 'error';
					error_span.textContent = this.saml_filesize_error_message.replace('%1$s', max_filesize);
					wrapper.append(error_span);

					textarea.classList.add('has-error');
					textarea.value = '';

					return;
				}

				const reader = new FileReader();

				reader.onload = function(e) {
					textarea.value = e.target.result;
				};

				reader.readAsText(file);
			});
			input.dispatchEvent(new MouseEvent('click'));
		}

		#addLdapSettingsEventListeners() {
			if (this.ldap_auth_enabled === null) {
				return;
			}

			this.ldap_servers_table.addEventListener('click', (e) => {
				if (e.target.classList.contains('disabled')) {
					return;
				}
				else if (e.target.classList.contains('js-add')) {
					this.editLdapServer();
				}
				else if (e.target.classList.contains('js-edit')) {
					this.editLdapServer(e.target.closest('tr'));
				}
				else if (e.target.classList.contains('js-remove')) {
					const table = e.target.closest('table');
					const userdirectoryid_input = e.target.closest('tr')
						.querySelector('input[name$="[userdirectoryid]"]');

					if (userdirectoryid_input !== null) {
						const input = document.createElement('input');
						input.type = 'hidden';
						input.name = 'ldap_removed_userdirectoryids[]';
						input.value = userdirectoryid_input.value;
						this.form.appendChild(input);
					}

					e.target.closest('tr').remove();

					if (table.querySelector('input[name="ldap_default_row_index"]:checked') === null) {
						const default_ldap = table.querySelector('input[name="ldap_default_row_index"]');

						if (default_ldap !== null) {
							default_ldap.checked = true;
						}
					}
				}
			});

			this.ldap_jit_status.addEventListener('change', this.#updateLdapFieldsState.bind(this));
			this.ldap_auth_enabled.addEventListener('change', this.#updateLdapFieldsState.bind(this));
		}

		#updateLdapFieldsState() {
			const ldap_disabled = !this.ldap_auth_enabled.checked;
			const provision_disabled = ldap_disabled || !this.ldap_jit_status.checked;

			this.ldap_provisioning_fields.forEach(field => field.toggleAttribute('disabled', ldap_disabled));
			this.#setTableVisiblityState(this.ldap_servers_table, ldap_disabled);
			this.#disableRemoveLinksWithUserGroups(this.ldap_servers_table);
			this.jit_provision_interval.toggleAttribute('disabled', provision_disabled);
		}

		_authFormSubmit() {
			const fields_to_trim = ['#http_strip_domains', '#idp_entityid', '#sso_url', '#slo_url',
				'#username_attribute', '#sp_entityid', '#nameid_format', '#saml_group_name', '#saml_user_username',
				'#saml_user_lastname', '#idp_certificate', '#sp_certificate', '#sp_private_key'
			];
			document.querySelectorAll(fields_to_trim.join(', ')).forEach((elem) => {
				elem.value = elem.value.trim();
			});

			let warnings = [];

			const auth_type = document.querySelector('[name=authentication_type]:checked').value;
			if (auth_type != this.db_authentication_type) {
				warnings.push(<?= json_encode(
					_('Changing the authentication method will reset all sessions, except the current one.')
				) ?>);
			}

			if (!this.#isSpCertificateRequired()) {
				const sp_certificate_input = document.getElementById('sp_certificate');
				const sp_private_key_input = document.getElementById('sp_private_key');

				if (this.saml_sp_certificate_exists && !sp_certificate_input.disabled && sp_certificate_input.value === '') {
					warnings.push(<?= json_encode(
						_('Current SP certificate will be deleted.')
					) ?>);
				}

				if (this.saml_sp_private_key_exists && !sp_private_key_input.disabled && sp_private_key_input.value === '') {
					warnings.push(<?= json_encode(
						_('Current SP private key will be deleted.')
					) ?>);
				}
			}

			return warnings.length > 0 ? confirm(warnings.join("\n")) : true;
		}

		_addLdapServers(ldap_servers, ldap_default_row_index) {
			for (const [row_index, ldap] of Object.entries(ldap_servers)) {
				ldap.row_index = row_index;
				ldap.is_default = (ldap.row_index == ldap_default_row_index) ? 'checked' : '';

				this.ldap_servers_table
					.querySelector('tbody')
					.appendChild(this._prepareServerRow(ldap));
			}
		}

		#disableRemoveLinksWithUserGroups(table) {
			table.querySelectorAll('[data-disable_remove] .js-remove').forEach(field => field.disabled = true);
		}

		_renderProvisionGroups(saml_provision_groups) {
			for (const [row_index, saml_provision_group] of Object.entries(saml_provision_groups)) {
				saml_provision_group.row_index = row_index;

				this.saml_provision_groups_table
					.querySelector('tbody')
					.appendChild(this._renderProvisionGroupRow(saml_provision_group));
			}
		}

		_renderProvisionMedia(saml_provision_media) {
			for (const [row_index, saml_media] of Object.entries(saml_provision_media)) {
				saml_media.row_index = row_index;

				this.saml_media_type_mapping_table
					.querySelector('tbody')
					.appendChild(this._renderProvisionMediaRow(saml_media));
			}
		}

		#setTableVisiblityState(table, readonly) {
			table.classList.toggle('disabled', readonly);
			table.querySelectorAll('a,input:not([type="hidden"]),button').forEach(node => {
				node.toggleAttribute('disabled', readonly);
				node.classList.toggle('disabled', readonly);
			});
		}

		editSamlProvisionGroup(row = null) {
			let popup_params = {};
			let row_index = 0;

			if (row !== null) {
				row_index = row.dataset.row_index;

				popup_params.name = row.querySelector(`[name="saml_provision_groups[${row_index}][name]"`).value;

				const user_groups = row.querySelectorAll(
					`[name="saml_provision_groups[${row_index}][user_groups][][usrgrpid]"`
				);
				if (user_groups.length) {
					popup_params.usrgrpid = [...user_groups].map(usrgrp => usrgrp.value);
				}

				const roleid = row.querySelector(`[name="saml_provision_groups[${row_index}][roleid]"`);
				if (roleid) {
					popup_params.roleid = roleid.value;
				}
			}
			else {
				while (this.saml_provision_groups_table.querySelector(`[data-row_index="${row_index}"]`) !== null) {
					row_index++;
				}

				popup_params = {
					add_group: 1,
					name: ''
				};
			}

			popup_params.idp_type = <?= IDP_TYPE_SAML ?>;

			const overlay = PopUp('popup.usergroupmapping.edit', popup_params,
				{dialogueid: 'user_group_edit', dialogue_class: 'modal-popup-medium'}
			);

			overlay.$dialogue[0].addEventListener('dialogue.submit', (e) => {
				const new_row = this._renderProvisionGroupRow({...e.detail, ...{row_index}});

				if (row === null) {
					this.saml_provision_groups_table.querySelector('tbody').appendChild(new_row);
				}
				else {
					row.replaceWith(new_row);
				}
			});
		}

		editSamlProvisionMedia(row = null) {
			let popup_params;
			let row_index = 0;

			if (row !== null) {
				row_index = row.dataset.row_index;

				popup_params = Object.fromEntries(
					[...row.querySelectorAll(`[name^="saml_provision_media[${row_index}]"]`)].map(
						i => [i.name.match(/\[([^\]]+)\]$/)[1], i.value]
				));
			}
			else {
				while (this.saml_media_type_mapping_table.querySelector(`[data-row_index="${row_index}"]`) !== null) {
					row_index++;
				}

				popup_params = {
					add_media_type_mapping: 1
				};
			}

			const overlay = PopUp('popup.mediatypemapping.edit', popup_params,
				{dialogueid: 'media_type_mapping_edit', dialogue_class: 'modal-popup-medium'}
			);

			overlay.$dialogue[0].addEventListener('dialogue.submit', (e) => {
				const saml_media_type_mapping = {...e.detail, ...{row_index: row_index}};

				if (row === null) {
					this.saml_media_type_mapping_table
						.querySelector('tbody')
						.appendChild(this._renderProvisionMediaRow(saml_media_type_mapping));
				}
				else {
					row.replaceWith(this._renderProvisionMediaRow(saml_media_type_mapping));
				}
			});
		}

		editLdapServer(row = null) {
			let popup_params;
			let row_index = 0;

			if (row !== null) {
				row_index = row.dataset.row_index;

				const provision_group_indexes = [...row.querySelectorAll(
					`[name^="ldap_servers[${row_index}][provision_groups]"][name$="[name]"]`
				)].map((element) => {
					let start = 33 + row_index.toString().length;
					let end = element.name.length - 7;
					return element.name.substring(start, end);
				});

				const provision_groups = provision_group_indexes.map((i) => {
					let user_groups = row.querySelectorAll(
						`[name="ldap_servers[${row_index}][provision_groups][${i}][user_groups][][usrgrpid]"`
					);
					let group_name = row.querySelector(
						`[name="ldap_servers[${row_index}][provision_groups][${i}][name]"`
					);
					let provision_group = {
						roleid: row.querySelector(
							`[name="ldap_servers[${row_index}][provision_groups][${i}][roleid]"`
						).value,
						user_groups: [...user_groups].map(usrgrp => usrgrp.value)
					}

					if (group_name) {
						provision_group.name = group_name.value;
					}

					return provision_group;
				});

				const provision_media_indexes = [...row.querySelectorAll(
					`[name^="ldap_servers[${row_index}][provision_media]"][name$="[name]"]`
				)].map((element) => {
					let start = 32 + row_index.toString().length;
					let end = element.name.length - 7;

					return element.name.substring(start, end);
				});
				const provision_media = provision_media_indexes.map((i) => {
					return Object.fromEntries(
						[...row.querySelectorAll(`[name^="ldap_servers[${row_index}][provision_media][${i}]"]`)].map(
							i => [i.name.match(/\[([^\]]+)\]$/)[1], i.value]
					));
				});

				popup_params = {
					row_index,
					add_ldap_server: 0,
					name: row.querySelector(`[name="ldap_servers[${row_index}][name]"`).value,
					host: row.querySelector(`[name="ldap_servers[${row_index}][host]"`).value,
					port: row.querySelector(`[name="ldap_servers[${row_index}][port]"`).value,
					base_dn: row.querySelector(`[name="ldap_servers[${row_index}][base_dn]"`).value,
					search_attribute: row.querySelector(`[name="ldap_servers[${row_index}][search_attribute]"`).value,
					search_filter: row.querySelector(`[name="ldap_servers[${row_index}][search_filter]"`).value,
					start_tls: row.querySelector(`[name="ldap_servers[${row_index}][start_tls]"`).value,
					bind_dn: row.querySelector(`[name="ldap_servers[${row_index}][bind_dn]"`).value,
					description: row.querySelector(`[name="ldap_servers[${row_index}][description]"`).value,
					provision_status: row.querySelector(`[name="ldap_servers[${row_index}][provision_status]"`).value,
					group_basedn: row.querySelector(`[name="ldap_servers[${row_index}][group_basedn]"`).value,
					group_name: row.querySelector(`[name="ldap_servers[${row_index}][group_name]"`).value,
					group_member: row.querySelector(`[name="ldap_servers[${row_index}][group_member]"`).value,
					user_ref_attr: row.querySelector(`[name="ldap_servers[${row_index}][user_ref_attr]"`).value,
					group_filter: row.querySelector(`[name="ldap_servers[${row_index}][group_filter]"`).value,
					group_membership: row.querySelector(`[name="ldap_servers[${row_index}][group_membership]"`).value,
					user_username: row.querySelector(`[name="ldap_servers[${row_index}][user_username]"`).value,
					user_lastname: row.querySelector(`[name="ldap_servers[${row_index}][user_lastname]"`).value,
					provision_groups,
					provision_media
				};

				const userdirectoryid_input = row.querySelector(`[name="ldap_servers[${row_index}][userdirectoryid]"`);
				const bind_password_input = row.querySelector(`[name="ldap_servers[${row_index}][bind_password]"`);

				if (userdirectoryid_input !== null) {
					popup_params['userdirectoryid'] = userdirectoryid_input.value;
				}

				if (bind_password_input !== null) {
					popup_params['bind_password'] = bind_password_input.value;
				}
			}
			else {
				while (document.querySelector(`#ldap-servers [data-row_index="${row_index}"]`) !== null) {
					row_index++;
				}

				popup_params = {
					row_index,
					add_ldap_server: 1
				};
			}

			const overlay = PopUp('popup.ldap.edit', popup_params,
				{dialogueid: 'ldap_edit', dialogue_class: 'modal-popup-generic'}
			);

			overlay.$dialogue[0].addEventListener('dialogue.submit', (e) => {
				const ldap = {...e.detail, ...{row_index: row_index}};

				if (row === null) {
					ldap.is_default = document.getElementById('ldap-servers')
							.querySelector('input[name="ldap_default_row_index"]:checked') === null;
					ldap.usrgrps = 0;

					this.ldap_servers_table
						.querySelector('tbody')
						.appendChild(this._prepareServerRow(ldap));
				}
				else {
					ldap.is_default = row.querySelector('input[name="ldap_default_row_index"]').checked === true;
					ldap.usrgrps = row.querySelector('.js-ldap-usergroups').textContent;

					row.parentNode.insertBefore(this._prepareServerRow(ldap), row);
					row.remove();
				}
			});
		}

		_prepareServerRow(ldap) {
			const template_ldap_server_row = new Template(this.templates.ldap_servers_row);
			const template = document.createElement('template');
			template.innerHTML = template_ldap_server_row.evaluate(ldap).trim();
			const row = template.content.firstChild;

			row.querySelector('[name="ldap_default_row_index"]').toggleAttribute('checked', ldap.is_default);

			if ('provision_groups' in ldap) {
				for (const [group_index, provision_group] of Object.entries(ldap.provision_groups)) {
					for (const [name, value] of Object.entries(provision_group)) {
						if (name === 'user_groups') {
							for (const usrgrp of value) {
								const input = document.createElement('input');
								input.name = 'ldap_servers[' + ldap.row_index + '][provision_groups][' + group_index + '][user_groups][][usrgrpid]';
								input.value = usrgrp.usrgrpid;
								input.type = 'hidden';
								row.appendChild(input);
							}
						}
						else {
							const input = document.createElement('input');
							input.name = 'ldap_servers[' + ldap.row_index + '][provision_groups][' + group_index + '][' + name + ']';
							input.value = value;
							input.type = 'hidden';
							row.appendChild(input);
						}
					}
				}
			}

			if ('provision_media' in ldap) {
				for (const [group_index, media] of Object.entries(ldap.provision_media)) {
					for (const [name, value] of Object.entries(media)) {
						if (name === 'mediatype_name') {
							continue;
						}
						const input = document.createElement('input');
						input.name = 'ldap_servers[' + ldap.row_index + '][provision_media][' + group_index + '][' + name + ']';
						input.value = value;
						input.type = 'hidden';
						row.appendChild(input);
					}
				}
			}

			const optional_fields = ['userdirectoryid', 'bind_password', 'start_tls', 'search_filter'];

			for (const field of optional_fields) {
				if (!(field in ldap)) {
					row.querySelector('input[name="ldap_servers[' + ldap.row_index + '][' + field + ']"]').remove();
				}
			}

			if (ldap.usrgrps > 0) {
				row.querySelector('.js-remove').disabled = true;
				row.dataset.disable_remove = true;
			}

			return row;
		}

		_renderProvisionGroupRow(saml_provision_group) {
			saml_provision_group.user_group_names = ('user_groups' in saml_provision_group)
				? Object.values(saml_provision_group.user_groups).map(user_group => user_group.name).join(', ')
				: '';

			const template = document.createElement('template');
			const template_saml_group_row = new Template(this.templates.saml_provisioning_group_row);
			template.innerHTML = template_saml_group_row.evaluate(saml_provision_group).trim();
			const row = template.content.firstChild;

			if ('user_groups' in saml_provision_group) {
				for (const user_group of Object.values(saml_provision_group.user_groups)) {
					const input = document.createElement('input');
					input.name = 'saml_provision_groups[' + saml_provision_group.row_index + '][user_groups][][usrgrpid]';
					input.value = user_group.usrgrpid;
					input.type = 'hidden';

					row.appendChild(input);
				}
			}

			if ('roleid' in saml_provision_group) {
				const input = document.createElement('input');
				input.name = 'saml_provision_groups[' + saml_provision_group.row_index + '][roleid]';
				input.value = saml_provision_group.roleid;
				input.type = 'hidden';

				row.appendChild(input);
			}

			return row;
		}

		_renderProvisionMediaRow(saml_media) {
			const template_saml_media_mapping_row = new Template(this.templates.saml_provisioning_media_row);
			const template = document.createElement('template');

			template.innerHTML = template_saml_media_mapping_row.evaluate(saml_media).trim();

			if (saml_media.userdirectory_mediaid === undefined) {
				template.content.firstChild.querySelector('[name$="[userdirectory_mediaid]"]').remove();
			}

			return template.content.firstChild;
		}

		#addMfaMethods(mfa_methods, mfa_default_row_index) {
			for (const [row_index, mfa] of Object.entries(mfa_methods)) {
				mfa.row_index = row_index;
				mfa.is_default = (mfa.row_index == mfa_default_row_index) ? 'checked' : '';

				this.mfa_table
					.querySelector('tbody')
					.appendChild(this.#prepareMfaRow(mfa));
			}
		}

		#prepareMfaRow(mfa) {
			const template_mfa_methods_row = new Template(this.templates.mfa_methods_row);
			const template = document.createElement('template');
			template.innerHTML = template_mfa_methods_row.evaluate(mfa).trim();
			const row = template.content.firstChild;

			row.querySelector('[name="mfa_default_row_index"]').toggleAttribute('checked', mfa.is_default);

			const optional_fields = ['mfaid', 'hash_function', 'code_length', 'api_hostname', 'clientid',
				'client_secret'
			];

			for (const field of optional_fields) {
				if (!(field in mfa)) {
					row.querySelector(`input[name="mfa_methods[${mfa.row_index}][${field}]"]`).remove();
				}
			}

			if (mfa.usrgrps > 0) {
				row.querySelector('.js-remove').disabled = true;
				row.dataset.disable_remove = true;
			}

			return row;
		}

		editMfaMethod(row = null) {
			let popup_params;
			let row_index = 0;

			if (row !== null) {
				row_index = row.dataset.row_index;

				popup_params = {
					row_index,
					add_mfa_method: 0,
					type: row.querySelector(`[name="mfa_methods[${row_index}][type]"`).value,
					name: row.querySelector(`[name="mfa_methods[${row_index}][name]"`).value,
					hash_function: row.querySelector(`[name="mfa_methods[${row_index}][hash_function]"`)?.value,
					code_length: row.querySelector(`[name="mfa_methods[${row_index}][code_length]"`)?.value,
					api_hostname: row.querySelector(`[name="mfa_methods[${row_index}][api_hostname]"`)?.value,
					clientid: row.querySelector(`[name="mfa_methods[${row_index}][clientid]"`)?.value,
					client_secret: row.querySelector(`[name="mfa_methods[${row_index}][client_secret]"`)?.value
				};

				const mfaid_input = row.querySelector(`[name="mfa_methods[${row_index}][mfaid]"`);

				if (mfaid_input !== null) {
					popup_params['mfaid'] = mfaid_input.value;
				}
			}
			else {
				while (document.querySelector(`#mfa-methods [data-row_index="${row_index}"]`) !== null) {
					row_index++;
				}

				popup_params = {
					row_index,
					add_mfa_method: 1
				};
			}

			const overlay = PopUp('mfa.edit', popup_params,
				{dialogueid: 'mfa_edit', dialogue_class: 'modal-popup-small'}
			);

			overlay.$dialogue[0].addEventListener('dialogue.submit', (e) => {
				const mfa = {...e.detail, row_index};

				if (row === null) {
					mfa.is_default = document.getElementById('mfa-methods')
						.querySelector('[name="mfa_default_row_index"]:checked') === null;
					mfa.usrgrps = 0;

					this.mfa_table
						.querySelector('tbody')
						.appendChild(this.#prepareMfaRow(mfa));
				}
				else {
					mfa.is_default = row.querySelector('[name="mfa_default_row_index"]').checked === true;
					mfa.usrgrps = row.querySelector('.js-mfa-usergroups').textContent;

					row.parentNode.insertBefore(this.#prepareMfaRow(mfa), row);
					row.remove();
				}
			});
		}
	};
</script>
